#include "FreeRTOS.h"
#include "queue.h"
#include "cmsis_os.h"
#include "module_config.h"

/* pop data from rx ring */
static void commInterfacePackProc(COMM_TYPE_ENUM type, uint8_t* data, uint32_t size)
{
    uint8_t len;
    uint8_t src_id;
    uint8_t dst_id;
    uint8_t cmd;
    uint8_t index;
    char TAG[4] = {0};
    COMM_TYPE_ENUM comm = COMM_MAX;

    if (type >= COMM_MAX || data == NULL)
    {
        return;
    }

    len = *(data+2);
    src_id = *(data+3);
    dst_id = *(data+4);
    cmd = *(data+5);
    index = *(data+6);
    
    if ((uint32_t)len+9 != size)
    {
        return;
    }

    /* check whether dst id match with comm */

    switch (dst_id)
    {
        /* log */
        case ID_DEBUG:
            snprintf(TAG, 4, "L%02x", src_id);
            if (src_id == ID_CGS)
            {
                LOG_TS(AM_LOG_LEVEL_WARNING, TAG, "%s\n", (char*)&data[8]);
            }
            else
            {
                LOG_TS(AM_LOG_LEVEL_WARNING, TAG, "%s\n", (char*)&data[7]);
            }
            break;

        /* at */
        case ID_AT:
            if (type == ACU_COMM_TYPE)
            {
                copy_at_cmd(1, (char*)&data[7], len);
            }
            else
            {
                at_transfer(g_u32Port, (char*)&data[7],len);
            }
            break;

        /* event */
        case ID_SELF:
            switch (src_id)
            {
                case ID_MR813:
                    doApCmd((uint8_t *)&data[7], len, index, cmd, src_id);
                    break;

                case ID_PDA:
                    doApPdaCmd((uint8_t *)&data[7], len, index, cmd, src_id);
                    break;

                case ID_VCU1:
                case ID_VCU2:
                    doMotorCmd((uint8_t *)&data[7], len, index, cmd, src_id);
                    break;

                case ID_CGS:
                    doStationCmd((uint8_t *)&data[7], len, index, cmd, src_id);
                    break;

                case ID_SELF:
                    if (boardCheck.comTest.enable == 1 && type == boardCheck.comTest.comType && len == 1 && index == COMM_TEST_INDEX && data[7] == COMM_TEST_DATA)
                    {
                        boardCheck.comTest.ackCnt++;
                    }
                    break;

            #ifdef TCU_MODULE
                case ID_TCU:
                    // process cmd to self
                     doTcuCmd((uint8_t *)&data[7], len, index, cmd, src_id);
                     break;
            #endif

                case 0x00:
                    if (index == COMM_MOTOR_ECU_ID_INDEX && cmd == COMM_CMD_CMAP_RD)    /* for VCU detect id */
                    {
                        motorInterface_responId(type);
                    }
                    break;

                default:
                    LOG_TS(AM_LOG_LEVEL_INFO, "COMM", "%02x->%02x %02x %02x %02x %02x%02x not support\n", src_id, dst_id, cmd, index, len, data[7], data[8]);
                    break;
            }
            //LOG_TS(AM_LOG_LEVEL_INFO, "COMM", "%02x->%02x %02x 02x %02x %02x%02x\n", src_id, dst_id, cmd, index, len, data[7], data[8]);
            break;

        /* transerfer */
        default:
            if(src_id == ID_SELF)
            {
                return;
            }

            comm = commGetCommTypeByUserId(dst_id);
            if (comm >= COMM_MAX)
            {
                LOG_TS(AM_LOG_LEVEL_INFO, "COMM", "%02x->%02x %02x %02x %02x %02x%02x not support\n", src_id, dst_id, cmd, index, len, data[7], data[8]);
            }
            else    /* support list see commUserIdTable */
            {
                if(dst_id == ID_CGS && cmd == COMM_CMD_IAP_BEGIN)
                {
                    setSubGIntoIAPStatus();
                }
                if(src_id == ID_PDA && dst_id == ID_CGS && cmd == COMM_CMD_CMAP_RD)
                {
                    pdaTurnToCgs(data);
                    break;
                }
            #ifdef TCU_MODULE
                if(dst_id == ID_TCU && cmd == COMM_CMD_IAP_BEGIN)
                {
                    tcu_set_ota_state(1);
                }
            #endif
                commTxRingPush(comm, data, size, 0);
            }
            break;
    }
}

static void comm_init(void)
{
    // uart_rx_startDMA((UART_HandleTypeDef*)commEntity[COMM_UART2].comm, commEntity[COMM_UART2].rx.buf, commEntity[COMM_UART2].rx.dmaBufSize);
    // uart_rx_startDMA((UART_HandleTypeDef*)commEntity[COMM_UART3].comm, commEntity[COMM_UART3].rx.buf, commEntity[COMM_UART3].rx.dmaBufSize);
    // uart_rx_startDMA((UART_HandleTypeDef*)commEntity[COMM_UART4].comm, commEntity[COMM_UART4].rx.buf, commEntity[COMM_UART4].rx.dmaBufSize);
    // uart_rx_startDMA((UART_HandleTypeDef*)commEntity[COMM_UART5].comm, commEntity[COMM_UART5].rx.buf, commEntity[COMM_UART5].rx.dmaBufSize);
    // uart_rx_startDMA((UART_HandleTypeDef*)commEntity[COMM_UART6].comm, commEntity[COMM_UART6].rx.buf, commEntity[COMM_UART6].rx.dmaBufSize);

    for (uint8_t i=0; i< sizeof(commEntity)/sizeof(commEntity[0]); i++)
    {
        if (commEntity[i].rx.dmaBufSize != 0 && commEntity[i].rx.buf != NULL)
        {
            HAL_UART_Receive_DMA((UART_HandleTypeDef*)commEntity[i].comm, commEntity[i].rx.buf, commEntity[i].rx.dmaBufSize);
            __HAL_UART_ENABLE_IT((UART_HandleTypeDef*)commEntity[i].comm, UART_IT_IDLE);
        }
    }
}

void comm_task(void *pvParameters)
{
    Msg_st    stMsg;

    comm_init();
    for (;;)
    {
        wl_queue_receive(WL_QUEUE_COMM_ID, &stMsg, 0xffffffff);
        switch (stMsg.u16MsgId)
        {
            /* receive process */
            #ifdef UART2_USING
            case WL_MSG_COMM_RX_UART2_DATA:
                commRxRingPopAndProcess(COMM_UART2, commInterfacePackProc);
                break;
            #endif

            #ifdef UART3_USING
            case WL_MSG_COMM_RX_UART3_DATA:
                commRxRingPopAndProcess(COMM_UART3, commInterfacePackProc);
                break;
            #endif

            #ifdef UART4_USING
            case WL_MSG_COMM_RX_UART4_DATA:
                commRxRingPopAndProcess(COMM_UART4, commInterfacePackProc);
                break;
            #endif

            #ifdef TCU_MODULE
            #ifdef UART5_USING
            case WL_MSG_COMM_RX_UART5_DATA:
                commRxRingPopAndProcess(COMM_UART5, commInterfacePackProc);
                break;
            #endif
            #endif

            #ifdef UART6_USING
            case WL_MSG_COMM_RX_UART6_DATA:
                commRxRingPopAndProcess(COMM_UART6, commInterfacePackProc);
                break;
            #endif

            case WL_MSG_COMM_RX_SPI1_DATA:
                commRxRingPopAndProcess(COMM_SPI1, commInterfacePackProc);
                break;

            /* flush */
            #ifdef UART1_USING
            case WL_MSG_COMM_TX_UART1_DATA:
                commTxRingPop_UART(COMM_UART1);
                break;
            #endif

            #ifdef UART2_USING
            case WL_MSG_COMM_TX_UART2_DATA:
                commTxRingPop_UART(COMM_UART2);
                break;
            #endif

            #ifdef UART3_USING
            case WL_MSG_COMM_TX_UART3_DATA:
                commTxRingPop_UART(COMM_UART3);
                break;
            #endif

            #ifdef UART4_USING
            case WL_MSG_COMM_TX_UART4_DATA:
                commTxRingPop_UART(COMM_UART4);
                break;
            #endif

            #ifdef TCU_MODULE
            #ifdef UART5_USING
            case WL_MSG_COMM_TX_UART5_DATA:
                commTxRingPop_UART(COMM_UART5);
                break;
            #endif
            #endif

            #ifdef UART6_USING
            case WL_MSG_COMM_TX_UART6_DATA:
                commTxRingPop_UART(COMM_UART6);
                break;
            #endif
                
            #ifdef TCU_MODULE  
            case WL_MSG_COMM_CLEAR_PAYLOAD:
                wl_ringbuf_clear_items(RINGBUF_TO_PAYLOAD_ID);
                break;
            #endif

            default:
                LOG_TS(AM_LOG_LEVEL_FATAL, "commtask", "msg id err: %d\r\n", stMsg.u16MsgId);
                break;
        }
    } 
}